#!/usr/bin/env python
# -*- coding: utf-8 -*-

import asyncio
import subprocess
from pathlib import Path
from typing import List, Optional, Tuple, Dict, Any
import logging
import os
import platform
import uuid

from .base_converter import BaseConverter, FileInfo

logger = logging.getLogger(__name__)

class DOCXConverter(BaseConverter):
    """DOCX/DOC转换器"""
    
    # 必需依赖应该为空，docling应该是可选的
    REQUIRED_DEPENDENCIES = {}
    
    # 可选依赖（注意：LibreOffice是系统级应用，不是Python包）
    OPTIONAL_DEPENDENCIES = {
        'docling': 'docling',
        'python-docx': 'python-docx'  # 新增python-docx支持
    }
    
    # 系统级依赖（需要单独安装）
    SYSTEM_DEPENDENCIES = {
        'libreoffice': {
            'check_cmd': ['libreoffice', '--version'],
            'install_info': {
                'ubuntu/debian': 'sudo apt-get install libreoffice',
                'centos/rhel': 'sudo yum install libreoffice',
                'windows': '请从 https://www.libreoffice.org/ 下载安装',
                'macos': 'brew install --cask libreoffice'
            }
        }
    }
    
    def __init__(self, temp_dir: Path, file_id: Optional[str] = None):
        super().__init__(temp_dir, file_id)
        # 检查系统级依赖
        self._check_system_dependencies()
    
    def _check_system_dependencies(self):
        """检查系统级依赖"""
        self.system_deps_available = {}
        
        for dep_name, dep_info in self.SYSTEM_DEPENDENCIES.items():
            try:
                # 减少超时时间并添加Windows兼容性
                creationflags = subprocess.CREATE_NO_WINDOW if os.name == 'nt' else 0
                result = subprocess.run(
                    dep_info['check_cmd'], 
                    capture_output=True, 
                    text=True, 
                    timeout=5,  # 减少到5秒
                    creationflags=creationflags
                )
                self.system_deps_available[dep_name] = result.returncode == 0
                if result.returncode == 0:
                    logger.debug(f"系统依赖 {dep_name} 可用")
                else:
                    logger.debug(f"系统依赖 {dep_name} 不可用: {result.stderr}")
            except (subprocess.TimeoutExpired, FileNotFoundError, subprocess.CalledProcessError) as e:
                self.system_deps_available[dep_name] = False
                logger.debug(f"系统依赖 {dep_name} 不可用: {e}")
    
    def is_libreoffice_available(self) -> bool:
        """检查LibreOffice是否可用"""
        return self.system_deps_available.get('libreoffice', False)
    
    def get_libreoffice_install_info(self) -> str:
        """获取LibreOffice安装信息"""
        system = platform.system().lower()
        
        install_info = self.SYSTEM_DEPENDENCIES['libreoffice']['install_info']
        
        if 'linux' in system:
            # 尝试检测Linux发行版
            try:
                with open('/etc/os-release', 'r') as f:
                    content = f.read().lower()
                    if 'ubuntu' in content or 'debian' in content:
                        return install_info['ubuntu/debian']
                    elif 'centos' in content or 'rhel' in content or 'fedora' in content:
                        return install_info['centos/rhel']
            except Exception:
                pass
            return install_info['ubuntu/debian']  # 默认使用ubuntu命令
        elif 'windows' in system:
            return install_info['windows']
        elif 'darwin' in system:
            return install_info['macos']
        else:
            return "请访问 https://www.libreoffice.org/ 下载适合您系统的版本"

    async def convert(self, file_path: Path, **kwargs) -> Tuple[str, List[FileInfo]]:
        """
        转换DOCX/DOC文件
        
        Args:
            file_path: 文件路径
            force_method: 强制使用的方法 ('docling', 'python-docx', 'pandoc')
            prefer_docling: 优先使用docling (默认True)
            **kwargs: 其他参数
            
        Returns:
            tuple: (markdown内容, 文件信息列表)
        """
        logger.info(f"转换文档文件: {file_path.name}")
        
        file_ext = file_path.suffix.lower()
        force_method = kwargs.get('force_method')
        prefer_docling = kwargs.get('prefer_docling', True)
        
        # 对于DOC文件，直接使用LibreOffice转换
        if file_ext == '.doc':
            if self.is_libreoffice_available():
                try:
                    logger.info(f"检测到DOC文件，将使用LibreOffice转换: {file_path.name}")
                    return await self._convert_doc_with_libreoffice(file_path, **kwargs)
                except Exception as e:
                    error_msg = f"LibreOffice转换DOC文件失败: {str(e)}"
                    logger.error(error_msg)
                    return await self._create_error_result(file_path, error_msg)
            else:
                error_msg = (
                    f"无法转换DOC文件，需要安装LibreOffice。\n\n"
                    f"安装命令：{self.get_libreoffice_install_info()}\n\n"
                    f"或者，您可以手动将DOC文件转换为DOCX格式后重试。"
                )
                logger.error(error_msg)
                return await self._create_error_result(file_path, error_msg)
        
        # 对于DOCX文件，根据参数选择转换方法
        if file_ext == '.docx':
            # 如果强制指定了方法
            if force_method:
                if force_method == 'docling' and self.is_dependency_available('docling'):
                    try:
                        return await self._convert_with_docling(file_path, **kwargs)
                    except Exception as e:
                        logger.error(f"强制使用docling转换失败: {e}")
                        raise
                elif force_method == 'python-docx':
                    try:
                        return await self._convert_docx_with_python_docx(file_path, **kwargs)
                    except Exception as e:
                        logger.error(f"强制使用python-docx转换失败: {e}")
                        raise
                elif force_method == 'pandoc':
                    try:
                        return await self._convert_with_pandoc(file_path, **kwargs)
                    except Exception as e:
                        logger.error(f"强制使用pandoc转换失败: {e}")
                        raise
                else:
                    error_msg = f"不支持的强制转换方法: {force_method} 或该方法不可用"
                    logger.error(error_msg)
                    return await self._create_error_result(file_path, error_msg)
            
            # 自动选择转换方法
            methods_to_try = []
            
            if prefer_docling and self.is_dependency_available('docling'):
                methods_to_try.append(('docling', self._convert_with_docling))
            
            methods_to_try.append(('python-docx', self._convert_docx_with_python_docx))
            
            if not prefer_docling and self.is_dependency_available('docling'):
                methods_to_try.append(('docling', self._convert_with_docling))
            
            # 依次尝试转换方法
            last_error = None
            for method_name, method_func in methods_to_try:
                try:
                    logger.info(f"尝试使用 {method_name} 转换DOCX文件")
                    return await method_func(file_path, **kwargs)
                except Exception as e:
                    logger.warning(f"{method_name} 转换失败: {e}")
                    last_error = e
                    continue
            
            # 所有方法都失败
            if last_error:
                raise last_error
        
        # 如果所有方法都失败
        available_methods = self.get_available_methods()
        if not available_methods:
            error_msg = (
                f"无法转换 {file_ext} 文件，缺少必要的依赖。\n"
                f"请安装以下依赖：\n"
                f"- 对于DOCX: pip install docling 或 pip install python-docx\n"
                f"- 对于DOC: 安装LibreOffice + pip install docling"
            )
            logger.error(error_msg)
            return await self._create_error_result(file_path, error_msg)
        
        # 如果有可用方法但都失败了
        error_msg = f"所有可用的转换方法都失败了。可用方法: {', '.join(available_methods)}"
        logger.error(error_msg)
        return await self._create_error_result(file_path, error_msg)
    
    async def _convert_docx_with_python_docx(self, file_path: Path, **kwargs) -> Tuple[str, List[FileInfo]]:
        """使用python-docx转换DOCX文件"""
        try:
            # 动态导入python-docx
            from docx import Document  # type: ignore
            
            logger.info("使用python-docx转换DOCX文件")
            
            # 在线程池中执行文档解析
            loop = asyncio.get_event_loop()
            
            def extract_docx_content():
                try:
                    doc = Document(str(file_path))
                    
                    # 提取文本内容
                    markdown_content = f"# DOCX文档转换结果\n\n"
                    markdown_content += f"**文件名**: {file_path.name}\n\n"
                    markdown_content += f"**转换工具**: python-docx\n\n"
                    markdown_content += f"## 文档内容\n\n"
                    
                    paragraphs = []
                    for paragraph in doc.paragraphs:
                        if paragraph.text.strip():
                            paragraphs.append(paragraph.text.strip())
                    
                    if paragraphs:
                        markdown_content += "\n\n".join(paragraphs)
                    else:
                        markdown_content += "*未提取到文本内容*"
                    
                    return markdown_content
                    
                except Exception as e:
                    logger.error(f"解析DOCX文件失败: {e}")
                    return f"# DOCX文档\n\n**文件名**: {file_path.name}\n\n**错误**: 解析DOCX文件失败: {str(e)}"
            
            markdown_content = await loop.run_in_executor(None, extract_docx_content)
            
            # 创建文件信息
            file_infos = []
            doc_file_info = self.create_file_info(file_path, str(uuid.uuid4()), "document")
            file_infos.append(doc_file_info)
            
            return markdown_content, file_infos
            
        except ImportError as e:
            logger.error(f"python-docx导入失败: {e}")
            raise ImportError(f"python-docx导入失败，请确认已正确安装: pip install python-docx")
    
    async def _convert_with_pandoc(self, file_path: Path, **kwargs) -> Tuple[str, List[FileInfo]]:
        """使用pandoc转换DOCX文件"""
        import subprocess
        import tempfile
        
        try:
            logger.info("使用pandoc转换DOCX文件")
            
            # 创建输出目录
            file_stem = file_path.stem
            output_dir = self.converter_work_dir / f"pandoc_{file_stem}"
            images_dir = output_dir / "images"
            images_dir.mkdir(parents=True, exist_ok=True)
            
            # 构建pandoc命令
            md_output = output_dir / f"{file_stem}.md"
            
            cmd = [
                'pandoc',
                '-s',  # standalone
                str(file_path),
                '-o', str(md_output),
                '--extract-media', str(images_dir)  # 提取图片到指定目录
            ]
            
            logger.info(f"执行pandoc命令: {' '.join(cmd)}")
            
            # 执行pandoc转换
            creationflags = subprocess.CREATE_NO_WINDOW if os.name == 'nt' else 0
            
            process = await asyncio.create_subprocess_exec(
                *cmd,
                stdout=asyncio.subprocess.PIPE,
                stderr=asyncio.subprocess.PIPE,
                creationflags=creationflags
            )
            
            stdout, stderr = await process.communicate()
            
            if process.returncode != 0:
                error_msg = f"pandoc执行失败: {stderr.decode('utf-8', errors='ignore')}"
                logger.error(error_msg)
                raise RuntimeError(error_msg)
            
            # 读取生成的markdown
            if md_output.exists():
                markdown_content = md_output.read_text(encoding='utf-8')
                
                # 添加转换信息
                conversion_info = f"**转换工具**: pandoc\n\n"
                markdown_content = conversion_info + markdown_content
            else:
                raise FileNotFoundError(f"pandoc未生成markdown文件: {md_output}")
            
            # 收集文件信息
            file_infos = []
            
            # 添加主文档信息
            doc_file_info = self.create_file_info(file_path, str(uuid.uuid4()), "document")
            file_infos.append(doc_file_info)
            
            # 查找生成的图片文件
            if images_dir.exists():
                for img_pattern in ['*.png', '*.jpg', '*.jpeg', '*.gif', '*.bmp', '*.svg']:
                    for img_file in images_dir.rglob(img_pattern):
                        img_file_info = self.create_file_info(img_file, str(uuid.uuid4()), "image")
                        file_infos.append(img_file_info)
            
            # 添加生成的markdown文件信息
            md_file_info = self.create_file_info(md_output, str(uuid.uuid4()), "document")
            file_infos.append(md_file_info)
            
            logger.info(f"pandoc转换成功: {len(file_infos)} 个文件")
            return markdown_content, file_infos
            
        except FileNotFoundError:
            error_msg = "pandoc未安装，请先安装pandoc"
            logger.error(error_msg)
            raise RuntimeError(error_msg)
        except Exception as e:
            error_msg = f"pandoc转换失败: {str(e)}"
            logger.error(error_msg)
            raise RuntimeError(error_msg)
    
    async def _convert_doc_with_libreoffice(self, file_path: Path, **kwargs) -> Tuple[str, List[FileInfo]]:
        """使用LibreOffice转换DOC文件到DOCX，然后进行正常转换"""
        import tempfile
        import shutil
        
        # 创建专用的临时目录，确保完整清理
        temp_libreoffice_dir = None
        
        try:
            # 在主临时目录下创建LibreOffice专用临时目录
            temp_libreoffice_dir = self.converter_work_dir / f"libreoffice_{uuid.uuid4().hex[:8]}"
            temp_libreoffice_dir.mkdir(exist_ok=True)
            
            # 创建输入和输出子目录
            input_dir = temp_libreoffice_dir / "input"
            output_dir = temp_libreoffice_dir / "output"
            input_dir.mkdir(exist_ok=True)
            output_dir.mkdir(exist_ok=True)
            
            # 复制DOC文件到输入目录（避免路径问题）
            temp_doc_path = input_dir / file_path.name
            shutil.copy2(file_path, temp_doc_path)
            
            # 构建LibreOffice命令，转换为DOCX
            expected_docx = output_dir / f"{file_path.stem}.docx"
            
            cmd = [
                'libreoffice',
                '--headless',
                '--convert-to', 'docx',
                '--outdir', str(output_dir),
                str(temp_doc_path)
            ]
            
            logger.info(f"使用LibreOffice转换DOC文件: {file_path.name}")
            logger.debug(f"LibreOffice命令: {' '.join(cmd)}")
            logger.debug(f"输入目录: {input_dir}")
            logger.debug(f"输出目录: {output_dir}")
            
            # 执行转换
            creationflags = subprocess.CREATE_NO_WINDOW if os.name == 'nt' else 0
            
            process = await asyncio.create_subprocess_exec(
                *cmd,
                stdout=asyncio.subprocess.PIPE,
                stderr=asyncio.subprocess.PIPE,
                creationflags=creationflags,
                cwd=str(temp_libreoffice_dir)  # 设置工作目录
            )
            
            stdout, stderr = await process.communicate()
            
            # 记录LibreOffice的输出用于调试
            if stdout:
                logger.debug(f"LibreOffice输出: {stdout.decode('utf-8', errors='ignore')}")
            if stderr:
                logger.debug(f"LibreOffice错误: {stderr.decode('utf-8', errors='ignore')}")
            
            if process.returncode != 0:
                error_msg = f"LibreOffice转换失败 (返回码: {process.returncode}): {stderr.decode('utf-8', errors='ignore')}"
                logger.error(error_msg)
                raise RuntimeError(error_msg)
            
            # 检查转换结果
            if not expected_docx.exists():
                # 尝试查找生成的文件
                generated_files = list(output_dir.glob("*.docx"))
                if generated_files:
                    expected_docx = generated_files[0]
                    logger.info(f"找到生成的DOCX文件: {expected_docx.name}")
                else:
                    # 列出输出目录内容用于调试
                    output_files = list(output_dir.iterdir())
                    logger.error(f"输出目录内容: {[f.name for f in output_files]}")
                    raise FileNotFoundError(f"LibreOffice未生成DOCX文件，预期位置: {expected_docx}")
            
            logger.info(f"LibreOffice转换成功，生成文件: {expected_docx}")
            
            # 使用docling或python-docx转换生成的DOCX
            if self.is_dependency_available('docling'):
                logger.info("使用docling处理转换后的DOCX文件")
                markdown_content, file_infos = await self._convert_with_docling(expected_docx, **kwargs)
            else:
                logger.info("使用python-docx处理转换后的DOCX文件")
                markdown_content, file_infos = await self._convert_docx_with_python_docx(expected_docx, **kwargs)
            
            # 移除转换说明信息，保持纯净的markdown内容
            
            # 更新第一个文件信息为原始DOC文件
            if file_infos:
                # 替换第一个文件信息（通常是转换后的DOCX）为原始DOC文件
                original_doc_info = self.create_file_info(file_path, file_infos[0].file_id, "document")
                file_infos[0] = original_doc_info
            
            return markdown_content, file_infos
                
        except subprocess.SubprocessError as e:
            logger.error(f"LibreOffice执行失败: {e}")
            raise RuntimeError(f"LibreOffice执行失败: {str(e)}")
        except Exception as e:
            logger.error(f"DOC转换失败: {e}")
            raise RuntimeError(f"DOC转换失败: {str(e)}")
        finally:
            # 检查是否为调试模式
            debug_mode = False
            try:
                from .work_dir_config import work_dir_config
                debug_mode = getattr(work_dir_config, '_debug_mode', False)
            except:
                pass
            
            # 清理LibreOffice临时目录（调试模式下保留）
            if temp_libreoffice_dir and temp_libreoffice_dir.exists():
                if debug_mode:
                    logger.info(f"调试模式，保留LibreOffice临时目录: {temp_libreoffice_dir}")
                else:
                    try:
                        shutil.rmtree(temp_libreoffice_dir)
                        logger.debug(f"清理LibreOffice临时目录: {temp_libreoffice_dir}")
                    except Exception as e:
                        logger.warning(f"清理LibreOffice临时目录失败: {e}")
    
    async def _create_error_result(self, file_path: Path, error_message: str) -> Tuple[str, List[FileInfo]]:
        """创建错误结果"""
        markdown_content = f"# 文档转换失败\n\n**文件名**: {file_path.name}\n\n**错误信息**: {error_message}"
        
        file_infos = []
        doc_file_info = self.create_file_info(file_path, str(uuid.uuid4()), "document")
        file_infos.append(doc_file_info)
        
        return markdown_content, file_infos
    
    async def _convert_with_docling(self, file_path: Path, **kwargs) -> Tuple[str, List[FileInfo]]:
        """使用docling转换DOCX文件 - 使用基类的通用方法"""
        logger.info(f"使用docling转换DOCX文件: {file_path.name}")
        return await self.convert_with_docling(file_path, **kwargs)
    

    
    def get_available_methods(self) -> List[str]:
        """获取可用的转换方法"""
        methods = []
        if self.is_dependency_available('docling'):
            methods.append('docling')
        if self.is_dependency_available('python-docx'):
            methods.append('python-docx')
        
        # 检查pandoc是否可用
        try:
            import subprocess
            result = subprocess.run(['pandoc', '--version'], 
                                  capture_output=True, text=True, timeout=5)
            if result.returncode == 0:
                methods.append('pandoc')
        except (FileNotFoundError, subprocess.TimeoutExpired):
            pass
        
        return methods
    
    def get_status_info(self) -> Dict[str, Any]:
        """获取转换器状态信息"""
        return {
            'docling_available': self.is_dependency_available('docling'),
            'libreoffice_available': self.is_libreoffice_available(),
            'libreoffice_install_info': self.get_libreoffice_install_info(),
            'available_methods': self.get_available_methods(),
            'doc_support': self.is_libreoffice_available(),  # DOC支持需要LibreOffice
            'docx_support': self.is_dependency_available('docling')  # DOCX支持需要docling
        } 